use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use core::cmp::Ordering;

#[repr(C)]
#[derive(Debug, Clone, Eq)]
pub struct Version {
    pub x: u16,
    pub y: u16,
    pub z: u16,
    pub b: u32,
}

impl TryFrom<&str> for Version {
    type Error = crate::Error;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        let mut ver = Version {
            x: 0,
            y: 0,
            z: 0,
            b: 0,
        };
        let mut index = 0;
        for item in value.split(".") {
            let v = item
                .parse::<u32>()
                .map_err(|_| crate::Error::InvalidParam)?;
            match index {
                0 => ver.x = v as u16,
                1 => ver.y = v as u16,
                2 => ver.z = v as u16,
                3 => ver.b = v,
                _ => {}
            }
            index += 1;
        }
        Ok(ver)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let src = ((self.x as u64) << 32) + ((self.y as u64) << 16) + self.z as u64;
        let dst = ((other.x as u64) << 32) + ((other.y as u64) << 16) + other.z as u64;
        let res = src.partial_cmp(&dst);
        if let Some(ref r) = res {
            if r.is_eq() {
                return self.b.partial_cmp(&other.b);
            }
        }
        res
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z && self.b == other.b
    }
}

impl ToString for Version {
    fn to_string(&self) -> String {
        format!("{}.{}.{}.{}", self.x, self.y, self.z, self.b)
    }
}
